#include "ThreadPool.h"
#include <chrono>
#include <iostream>
#include <functional>
#include <type_traits>

namespace CommonSupport
{
    TaskQueue::TaskQueue()
    {
    }

    TaskQueue::~TaskQueue()
    {
        clear();
    }

    void TaskQueue::addTask(Task *task)
    {
        queueMutex.lock();
        taskQueue.push(task);
        queueMutex.unlock();
        queueCondition.notify_one();
    }

    Task *TaskQueue::takeTask()
    {
        lock_guard<mutex> locker(queueMutex);
        queueCondition.wait(
            queueMutex,
            [this]() -> bool
            {
                return !taskQueue.empty();
            }
        );
        Task *task = taskQueue.front();
        taskQueue.pop();
        return task;
    }

    int TaskQueue::size()
    {
        lock_guard<mutex> locker(queueMutex);
        return taskQueue.size();
    }

    int TaskQueue::empty()
    {
        lock_guard<mutex> locker(queueMutex);
        return taskQueue.empty();
    }

    void TaskQueue::clear()
    {
        lock_guard<mutex> locker(queueMutex);
        while (!taskQueue.empty())
        {
            Task *task = taskQueue.front();
            taskQueue.pop();
            delete task;
        }
    }

    ThreadPool::ThreadPool(int min, int max) : minNum(min), maxNum(max)
    {
        shutdown = false;
        liveNum = 0;
        busyNum = 0;

#ifdef _WIN32
        managerThread = thread(bind(ThreadPool::managerProcess, this));
#elif __linux__ | __APPLE__
        managerThread = thread([this]()-> void { managerProcess(); });
#endif

        for (int i = 0; i < min; ++i)
        {
            createWorkerProcess();
        }
    }

    ThreadPool::~ThreadPool()
    {
        shutdown = true;

        if (managerThread.joinable())
            managerThread.join();

        taskQueue.clear();
        for (int i = 0; i < liveNum; ++i)
        {
            taskQueue.addTask(new Task(false));
        }
        poolCondition.wait(
            poolMutex,
            [this]() -> bool
            {
                return liveNum <= 0;
            });
    }

    void ThreadPool::addTask(TaskCallBack taskCallBack)
    {
        this->addTask(taskCallBack, nullptr);
    }

    void ThreadPool::addTask(TaskCallBack taskCallBack, void *arg)
    {
        this->addTask(taskCallBack, arg, nullptr);
    }

    void ThreadPool::addTask(TaskCallBack taskCallBack, void *arg, TaskDeleter deleter)
    {
        taskQueue.addTask(new Task(true, taskCallBack, arg, deleter));
    }

    void ThreadPool::managerProcess()
    {
        int NUMBER = 2;

        while (!shutdown)
        {
            this_thread::sleep_for(chrono::seconds(3));

            int queueSize = taskQueue.size();

            poolMutex.lock();
            int liveNum = this->liveNum;
            int busyNum = this->busyNum;
            poolMutex.unlock();

            int idleNum = liveNum - busyNum;

            cout << "管理线程: ID=" + getCurrentThreadId() + "，开始工作:\n" + 
                    "当前线程最小：" + to_string(minNum) + "\n" + 
                    "当前线程最大：" + to_string(maxNum) + "\n" + 
                    "当前存活线程：" + to_string(liveNum) + "\n" + 
                    "当前忙碌线程：" + to_string(busyNum) + "\n" + 
                    "当前闲置线程：" + to_string(idleNum) + "\n" + 
                    "当前队列大小：" + to_string(queueSize) + "\n";

            if (idleNum == queueSize)
            {
            }
            else if (idleNum > queueSize)
            {
                if (liveNum > minNum && liveNum > (busyNum * 2))
                {
                    for (int i = 0; i < NUMBER; ++i)
                    {
                        taskQueue.addTask(new Task(false));
                    }
                }
            }
            else
            {
                if (liveNum < maxNum)
                {
                    for (int i = 0; i < NUMBER; ++i)
                    {
                        createWorkerProcess();
                    }
                }
            }
        }
    }

    void ThreadPool::createWorkerProcess()
    {
        lock_guard<mutex> locker(poolMutex);
        if (liveNum >= maxNum)
            return;
#ifdef _WIN32
        thread workerThread(bind(ThreadPool::workerProcess, this));
#elif __linux__ | __APPLE__
        thread workerThread([this]()-> void { workerProcess(); });
#endif
        if (workerThread.joinable())
        {
            workerThread.detach();
            liveNum++;
        }
    }

    void ThreadPool::workerProcess()
    {
        while (true)
        {
            Task *task = taskQueue.takeTask();
            if (!task->needRun)
            {
                delete task;
                if (!shutdown && liveNum <= minNum)
                {
                    continue;
                }
                break;
            }

            poolMutex.lock();
            busyNum++;
            poolMutex.unlock();

            task->callBack(task->arg);

            poolMutex.lock();
            busyNum--;
            poolMutex.unlock();
            delete task;
        }

        poolMutex.lock();
        liveNum--;
        poolMutex.unlock();

        poolCondition.notify_one();
    }
};